import 'dart:io';
import 'package:csv/csv.dart';
import 'package:path_provider/path_provider.dart';
import 'package:sleep/single/wave_show_model.dart';

const sleepcsv = 'sleep_breathewave'; //sleep_breathe--_1029
const sleepWaveCsv = 'sleep_breathecalc'; //sleep_breathe--_1029
const sleepplusecsv = 'sleep_pulsewave'; //fatigue_pulsewave_1029
const sleeppluseWaveCsv = 'sleep_pulsecalc'; //fatigue_pulsewave_1029

const fatiguecsv = 'fatigue_blinkwave'; //fatigue_blink--_1029
const fatigueWaveCsv = 'fatigue_blinkcalc'; //fatigue_blinkwave_1029
const fatigueplusecsv = 'fatigue_pulsewave'; //fatigue_pulsewave_1029
const fatiguepluseWaveCsv = 'fatigue_pulsecalc'; //fatigue_pulsewave_1029

class ExportModel {
  File? file;
  int index = 1;
  String? startTime;
  int? startTimeSp;
  final String path;

  ExportModel(this.path);
}

enum CsvType {
  pluseFatigue,
  pluseSleep,
  pluseSleepWave,
  pluseFatigueWave,
  sleep,
  fatigue,
  sleepwave,
  fatiguewave,
}

class Export {
  static Export? _manger;
  Export._();
  static Export share() {
    _manger ??= Export._();
    return _manger!;
  }

  ExportModel sleepPluse = ExportModel(sleepplusecsv);
  ExportModel pluseSleepWave = ExportModel(sleeppluseWaveCsv);
  ExportModel sleep = ExportModel(sleepcsv);
  ExportModel sleepWave = ExportModel(sleepWaveCsv);

  ExportModel faitgue = ExportModel(fatiguecsv);
  ExportModel fatigueWave = ExportModel(fatigueWaveCsv);
  ExportModel fatiguePluse = ExportModel(fatigueplusecsv);
  ExportModel pluseFatigueWave = ExportModel(fatiguepluseWaveCsv);

  String localPath = '/storage/emulated/0/Download/';

  setup() async {}

  createFatigue() {
    create(CsvType.pluseFatigue);
    create(CsvType.pluseFatigueWave, head: PluseShowModel.toFKey());
    create(CsvType.fatiguewave, head: FtaigueShowData.toKey());
    create(CsvType.fatigue);
  }

  createSleep() {
    create(CsvType.pluseSleep);
    create(CsvType.pluseSleepWave, head: PluseShowModel.toSleepKey());
    create(CsvType.sleepwave, head: SleepShowData.toKey());
    create(CsvType.sleep);
  }

  finishFatigue() {
    finish(CsvType.pluseFatigue);
    finish(CsvType.pluseFatigueWave);
    finish(CsvType.fatiguewave);
    finish(CsvType.fatigue);
  }

  finshSleep() {
    finish(CsvType.pluseSleep);
    finish(CsvType.pluseSleepWave);
    finish(CsvType.sleepwave);
    finish(CsvType.sleep);
  }

  create(CsvType type, {List<String>? head}) {
    final datePath = timePath();
    final model = getModel(type);
    final fullPath = '$localPath${model.path}$datePath.csv';

    model.file = File(fullPath);
    header(type, head);
  }

  timePath() {
    final date = DateTime.now();
    return '${date.month}${date.day}-${date.hour}${date.minute}${date.second}';
  }

  save(List<double>? datas, CsvType type, {List<List<String>>? dataStr}) {
    final model = getModel(type);
    if (model.file == null) return;
    if ((dataStr == null || dataStr.isEmpty) &&
        (datas == null || datas.isEmpty)) return;

    final time = DateTime.now().millisecondsSinceEpoch - getStartTime(type);
    // final index = getStartIndex(model.index, type);

    if (time > 1000 * 60 * 60) {
      newFileclear(type);
      create(type);
    }
    List<List<dynamic>> rows = [];

    if (datas != null) {
      for (var i = 0; i < datas.length; i++) {
        final data = datas[i];
        rows.add([
          (model.index + i).toString(),
          data.toStringAsFixed(6),
        ]);
      }

      model.index += datas.length;
    }

    if (dataStr != null) {
      for (var i = 0; i < dataStr.length; i++) {
        rows.add([(model.index + i).toString(), ...dataStr[i]]);
      }

      model.index += dataStr.length;
    }

    String csv = const ListToCsvConverter().convert(rows);

    getFile(type)?.writeAsStringSync('\r\n$csv', mode: FileMode.append);
  }

  header(CsvType type, List<String>? head) {
    List<List<dynamic>> rows = [];

    rows.add(["Sample Interval", "0.004"]);
    rows.add(["Vertical Offset", "0"]);
    rows.add([
      'StartTime',
      getStartTimeStr(type),
    ]);
    rows.add([]);
    rows.add([]);
    if (head == null) {
      rows.add(["index", "value"]);
    } else {
      rows.add(["index", ...head]);
    }

    String csv = const ListToCsvConverter().convert(rows);
    getFile(type)?.writeAsStringSync(csv, mode: FileMode.append);
  }

  newFileclear(CsvType type) {
    final model = getModel(type);
    model.file = null;
    model.index = 0;
    model.startTimeSp = null;
  }

  finish(CsvType type) {
    final model = getModel(type);
    model.file = null;
    model.index = 1;
    model.startTimeSp = null;
    model.startTime = null;
  }

  File? getFile(CsvType type) {
    return getModel(type).file;
  }

  getStartIndex(int startIndex, CsvType type) {
    final file = getFile(type);
    if (file == null) return null;

    int? index;

    final model = getModel(type);
    model.index ??= startIndex;
    index = model.index;

    return index;
  }

  getStartTime(CsvType type) {
    final file = getFile(type);
    if (file == null) return null;
    final date = DateTime.now().millisecondsSinceEpoch;
    int? start;
    final model = getModel(type);
    model.startTimeSp ??= date;
    start = model.startTimeSp;

    return start;
  }

  getStartTimeStr(CsvType type) {
    final file = getFile(type);
    if (file == null) return null;
    final date = DateTime.now();
    final startStr =
        '${date.year}-${date.month}-${date.day} ${date.hour}:${date.minute}:${date.second}';
    String? start;
    final model = getModel(type);
    model.startTime ??= startStr;
    start = model.startTime;

    return start;
  }

  ExportModel getModel(CsvType type) {
    ExportModel model;
    switch (type) {
      case CsvType.fatigue:
        {
          model = faitgue;
          break;
        }
      case CsvType.sleep:
        {
          model = sleep;
          break;
        }
      case CsvType.pluseFatigue:
        {
          model = fatiguePluse;
          break;
        }
      case CsvType.pluseSleep:
        {
          model = sleepPluse;
          break;
        }
      case CsvType.pluseSleepWave:
        {
          model = pluseSleepWave;
          break;
        }
      case CsvType.pluseFatigueWave:
        {
          model = pluseFatigueWave;
          break;
        }
      case CsvType.sleepwave:
        {
          model = sleepWave;
          break;
        }
      case CsvType.fatiguewave:
        {
          model = fatigueWave;
          break;
        }
    }

    return model;
  }
}
